package com.ruoyi.hazard.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.bean.BeanValidators;
import com.ruoyi.hazard.domain.HazardAlarmInfo;
import com.ruoyi.hazard.domain.HazardAlarmRecord;
import com.ruoyi.hazard.domain.HazardInfo;
import com.ruoyi.hazard.domain.dto.HazardInfoDto;
import com.ruoyi.hazard.domain.qo.HazardInfoPageQo;
import com.ruoyi.hazard.domain.qo.HazardInfoQo;
import com.ruoyi.hazard.domain.vo.HazardAlarmVo;
import com.ruoyi.hazard.domain.vo.HazardAmountAnalysisVo;
import com.ruoyi.hazard.domain.vo.HazardInfoVo;
import com.ruoyi.hazard.domain.vo.HazardStatisticsVo;
import com.ruoyi.hazard.mapper.HazardInfoMapper;
import com.ruoyi.hazard.service.HazardAlarmInfoService;
import com.ruoyi.hazard.service.HazardAlarmRecordService;
import com.ruoyi.hazard.service.HazardInfoService;
import com.ruoyi.system.service.ISysDeptService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.validation.Validator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 文件信息表（存储Minio文件元数据信息）(FileInfo)表服务实现类
 *
 * @author admin
 * @since 2025-07-23 10:50:03
 */
@Slf4j
@Service("hazardInfoService")
public class HazardInfoServiceImpl extends ServiceImpl<HazardInfoMapper, HazardInfo> implements HazardInfoService {

//    @Autowired
//    private FileInfoService fileInfoService;

    @Autowired
    private HazardAlarmInfoService hazardAlarmInfoService;
    @Autowired
    private HazardAlarmRecordService hazardAlarmRecordService;


    @Autowired
    protected Validator validator;
    @Autowired
    private ISysDeptService sysDeptService;


//    @Override
//    @DataScope
//    public IPage<HazardInfoVo> getPage(LambdaQueryWrapper<HazardInfo> qw, int pageNum, int pageSize) {
//        IPage<HazardInfo> page = this.page(new Page(pageNum, pageSize), qw);
//        IPage<HazardInfoVo> pageVo = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
//        List<HazardInfoVo> hazardInfoVos = page.getRecords().stream().map(this::toVo).collect(Collectors.toList());
//        pageVo.setRecords(hazardInfoVos);
//        return pageVo;
//    }

    @Override
    public void hazardAlarm(){
        //清楚已经过期的弹框内容
        Date today = DateUtils.getNowDate();
        hazardAlarmInfoService.remove(new LambdaQueryWrapper<HazardAlarmInfo>().le(HazardAlarmInfo::getNextDate,today));
        List<HazardAlarmInfo> dbAlarmInfos = hazardAlarmInfoService.list();
        log.info("已经存在的弹框个数：{}",dbAlarmInfos.size());
        List<HazardInfoDto> listDto = this.baseMapper.getUnfinishedHazardInfo();
        for (HazardInfoDto hazardInfoDto : listDto) {
            // 设置查询条件，只比较日期部分
            LambdaQueryWrapper<HazardAlarmInfo> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(HazardAlarmInfo::getHazardId, hazardInfoDto.getId());
            queryWrapper.eq(HazardAlarmInfo::getStartDate, DateUtils.getDate());
//            HazardAlarmInfo hazardAlarmInfo = hazardAlarmInfoService.getOne(queryWrapper);
//            if(hazardAlarmInfo!=null){
//                continue;
//            }

            //获取整改期限大于当前时间
            Integer d1 =DateUtils.differentDaysByMillisecond3(hazardInfoDto.getDeadline(),today);
            //获取整改期限与检查日期之间的时间差
            log.info("隐患id为{}的隐患距离整改期限还有{}天",hazardInfoDto.getId(),d1);
            Integer d2 = DateUtils.differentDaysByMillisecond3(hazardInfoDto.getCheckDate(),hazardInfoDto.getDeadline());
            log.info("隐患id为{}的隐患整改日期与检查日期有{}天",hazardInfoDto.getId(),d2);

            //从中取出deadline<today的隐患（延期的），算出今天所在的预警段，比如1号-3号，4号-6号，7号-9号，假设今天是8号，那就是应该是7-9号段，
            // 取预警表从中的数据进行比对，一条隐患在预警表中最多一条记录，如果有start=7号&&next=9号的记录，则说明不需要更新，
            // 否则其它情况，都应该创建新记录，删掉旧记录（这样deltaId的机制就会起作用）（另外如果查出来有不配置的预警区间，说明隐患信息有更新，重新预警也是正常的）
            //再从剩余的隐患中取出deadline-checkDate>30天的隐患，算出今天所在的预警段，则从时间过半开始，每5天提醒一次
            if ( d1>=1) {
                Date begin = DateUtils.addDays(hazardInfoDto.getDeadline(),1);
                int turn = DateUtils.differentDaysByMillisecond3(begin,today)/3;
                Date start = DateUtils.addDays(begin,turn*3);
                Date end = DateUtils.addDays(start,3);
                HazardAlarmInfo alarmInfo =dbAlarmInfos.stream().filter(info -> info.getHazardId().equals(hazardInfoDto.getId())
                        && info.getAlarmDelayed().equals(1)
                        && DateUtils.differentDaysByMillisecond(info.getStartDate(),start)==0
                        && DateUtils.differentDaysByMillisecond(info.getNextDate(),end)==0).findFirst().orElse(null);

                log.info("隐患id为{}的隐患已经延期，第{}轮，开始时间：{}，结束时间:{}",hazardInfoDto.getId(),turn,DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,start),
                        DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,end));
                //没有数据就创建数据
                if(alarmInfo==null){
                    log.info("隐患id为{}的隐患已经延期，新增一条弹框内容",hazardInfoDto.getId());
                    HazardAlarmInfo hazardAlarmInfo = new HazardAlarmInfo();
                    hazardAlarmInfo.setHazardId(hazardInfoDto.getId());
                    hazardAlarmInfo.setStartDate(start);
                    hazardAlarmInfo.setNextDate(end);
                    hazardAlarmInfo.setAlarmDelayed(1);
                    hazardAlarmInfoService.save(hazardAlarmInfo);
                }else{
                    log.info("存在id为{}的隐患延期内容,弹框id:{},从列表中删除",hazardInfoDto.getId(),alarmInfo.getId());
                    dbAlarmInfos.remove(alarmInfo);
                }
            }else if(d2>=30){
                Date alarmDate = DateUtils.addDays(hazardInfoDto.getCheckDate(),d2/2);
                log.info("隐患id为{}的隐患距离检查日期：{},过半的日期是：{}",hazardInfoDto.getId(),DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,hazardInfoDto.getCheckDate())
                                                                                    ,DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,alarmDate));
                Date begin = DateUtils.addDays(alarmDate,1);
                int turn = DateUtils.differentDaysByMillisecond3(begin,today)/5;
                Date start = DateUtils.addDays(begin,turn*5);
                Date end = DateUtils.addDays(start,5);

                HazardAlarmInfo alarmInfo =dbAlarmInfos.stream().filter(info -> info.getHazardId().equals(hazardInfoDto.getId())
                        && info.getAlarmDelayed().equals(0)
                        && DateUtils.differentDaysByMillisecond(info.getStartDate(),start)==0
                        && DateUtils.differentDaysByMillisecond(info.getNextDate(),end)==0).findFirst().orElse(null);

                log.info("隐患id为{}的隐患已经超时，第{}轮，开始时间：{}，结束时间:{}",hazardInfoDto.getId(),turn,DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,start),
                        DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,end));
                if(alarmInfo==null){
                    log.info("隐患id为{}的隐患已经超时，新增一条弹框内容",hazardInfoDto.getId());
                    HazardAlarmInfo hazardAlarmInfo = new HazardAlarmInfo();
                    hazardAlarmInfo.setHazardId(hazardInfoDto.getId());
                    hazardAlarmInfo.setStartDate(start);
                    hazardAlarmInfo.setNextDate(end);
                    hazardAlarmInfo.setAlarmDelayed(0);
                    hazardAlarmInfoService.save(hazardAlarmInfo);
                } else{
                    log.info("存在id为{}的隐患超时内容,弹框id:{},从列表中删除",hazardInfoDto.getId(),alarmInfo.getId());
                    dbAlarmInfos.remove(alarmInfo);
                }
            }else{
                hazardAlarmInfoService.remove(new LambdaQueryWrapper<HazardAlarmInfo>().eq(HazardAlarmInfo::getHazardId,hazardInfoDto.getId()));
            }
        }
        log.info("需要删除已经存在的弹框个数：{}",dbAlarmInfos.size());
        hazardAlarmInfoService.removeByIds(dbAlarmInfos);
    }


    @Override
    public IPage<HazardInfoVo> getPage(HazardInfoPageQo qo) {
        Integer pageNum = qo.getPageNum()==null? 1:qo.getPageNum();
        Integer pageSize = qo.getPageSize()==null?10:qo.getPageSize();
        IPage<HazardInfoDto> page = new Page<>(pageNum, pageSize);
        IPage<HazardInfoDto> pageVo = this.baseMapper.getpageHazard(page,qo);
        IPage<HazardInfoVo> pageVos = new Page<>(pageVo.getCurrent(), pageVo.getSize(), pageVo.getTotal());
        List<HazardInfoVo> hazardInfoVos = pageVo.getRecords().stream().map(this::toVo).collect(Collectors.toList());
        pageVos.setRecords(hazardInfoVos);
        return pageVos;
    }

    @Override
    public List<HazardInfoDto> getList(HazardInfoQo qo) {
        List<HazardInfoDto> listDto = this.baseMapper.getListHazard(qo);
        List<HazardInfoVo> listVo = listDto.stream().map(this::toVo).collect(Collectors.toList());
        return listDto;
    }

    @Override
    public String importData(List<HazardInfoVo> hazardInfoVos, boolean updateSupport) {
        if (CollectionUtils.isEmpty(hazardInfoVos))
        {
            throw new ServiceException("导入隐患数据不能为空！");
        }
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        for (HazardInfoVo hazardInfoVo : hazardInfoVos){
            try
            {

                SysDept dept =sysDeptService.selectDeptByDeptName(hazardInfoVo.getDeptName());

               if(StringUtils.isNull(dept)){
                   failureNum++;
                   failureMsg.append("<br/>" + failureNum + "、单位 " + hazardInfoVo.getDeptName() + " 不存在");
               }else if(SecurityUtils.getDeptId() !=100L && dept.getParentId() != SecurityUtils.getDeptId()) {
                   failureNum++;
                   failureMsg.append("<br/>" + failureNum + "、非单位 " + hazardInfoVo.getDeptName() + "人员，不可导入");
               }else {
                   // 验证是否存在这个隐患
                   hazardInfoVo.setDeptId(dept.getDeptId());
                   HazardInfo hazardInfo = this.baseMapper.selectById(hazardInfoVo.getId());
                   //检查日期为空 默认当前日期
                   if(hazardInfoVo.getCheckDate() == null){
                       hazardInfoVo.setCheckDate(new Date());
                   }
                   //限期为空 默认N天
                   if("重大".equals(hazardInfoVo.getLevel())){
                       if(StringUtils.hasText(hazardInfoVo.getSuperviseLevel())){
                           hazardInfoVo.setSuperviseLevel("省局督办");
                       }
                       if(hazardInfoVo.getDeadline() == null){
                           hazardInfoVo.setDeadline(DateUtils.addDays(hazardInfoVo.getCheckDate(), 90));
                       }
                   }else if("一般（黄）".equals(hazardInfoVo.getLevel()) && hazardInfoVo.getDeadline() == null){
                       hazardInfoVo.setDeadline(DateUtils.addDays(hazardInfoVo.getCheckDate(), 30));
                   }else if("一般（蓝）".equals(hazardInfoVo.getLevel()) && hazardInfoVo.getDeadline() == null){
                       hazardInfoVo.setDeadline(DateUtils.addDays(hazardInfoVo.getCheckDate(), 5));
                   }

                   if (StringUtils.isNull(hazardInfo) && hazardInfoVo.getId() ==null) {

                       HazardInfo hazardInfo1 = this.toEntity(hazardInfoVo);

                       this.save(hazardInfo1);
                       successNum++;
                       successMsg.append("<br/>" + successNum + "、隐患描述 " + hazardInfoVo.getDescription() + " 导入成功");
                   } else if (updateSupport) {
                       HazardInfo hazardInfo1 = this.toEntity(hazardInfoVo);
                       BeanValidators.validateWithException(validator, hazardInfo1);
                       this.baseMapper.updateById(hazardInfo1);
                       successNum++;
                       successMsg.append("<br/>" + successNum + "、隐患描述 " + hazardInfoVo.getDescription()  + " 更新成功");
                   } else {
                       failureNum++;
                       failureMsg.append("<br/>" + failureNum + "、隐患描述 " + hazardInfoVo.getDescription() + " 已存在");
                   }
               }

            }catch (Exception e){
                log.error("导入隐患数据失败",e);
                failureNum++;
                String msg = "<br/>" + failureNum + "、隐患描述 " + hazardInfoVo.getDescription() + " 导入失败：";
                failureMsg.append(msg + e.getMessage());
            }
        }

        if (failureNum > 0)
        {
            failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            throw new ServiceException(failureMsg.toString());
        }
        else
        {
            successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条，数据如下：");
        }
        return successMsg.toString();
    }

    @Override
    public HazardInfoVo toVo(HazardInfo hazardInfo){
        HazardInfoVo vo = new HazardInfoVo();
//        BeanUtils.copyBeanProp(vo,hazardInfo,"attachmentsDocument","attachmentsImage");
//        String attachmentsDocument = hazardInfo.getAttachmentsDocument();
//        if(StringUtils.hasText(attachmentsDocument)){
//            List fileUrl = Arrays.asList(attachmentsDocument.split(","));
//            vo.setAttachmentsDocument(fileUrl);
//        }
//        String attachmentsImage = hazardInfo.getAttachmentsImage();
//        if(StringUtils.hasText(attachmentsImage)){
//            List fileUrl = Arrays.asList(attachmentsImage.split(","));
//            vo.setAttachmentsImage(fileUrl);
//        }

        BeanUtils.copyBeanProp(vo,hazardInfo);
        return vo;
    }

    public HazardInfoVo toVo(HazardInfoDto hazardInfo){
        HazardInfoVo vo = new HazardInfoVo();
//        BeanUtils.copyBeanProp(vo,hazardInfo, "attachmentsDocument","attachmentsImage");
//        String attachmentsDocument = hazardInfo.getAttachmentsDocument();
//        if(StringUtils.hasText(attachmentsDocument)){
//            List fileUrl = Arrays.asList(attachmentsDocument.split(","));
//            vo.setAttachmentsDocument(fileUrl);
//        }
//        String attachmentsImage = hazardInfo.getAttachmentsImage();
//        if(StringUtils.hasText(attachmentsImage)){
//            List fileUrl = Arrays.asList(attachmentsImage.split(","));
//            vo.setAttachmentsImage(fileUrl);
//        }
        BeanUtils.copyBeanProp(vo,hazardInfo);
        return vo;
    }

    @Override
    public HazardInfo toEntity(HazardInfoVo vo){
        HazardInfo hazardInfo = new HazardInfo();

//        BeanUtils.copyBeanProp(hazardInfo,vo, "attachmentsDocument","attachmentsImage");
//        List<String> attachmentsDocument = vo.getAttachmentsDocument();
//        if(attachmentsDocument != null && !attachmentsDocument.isEmpty()) {
//            hazardInfo.setAttachmentsDocument(String.join(",", attachmentsDocument.stream().map(String::valueOf).collect(Collectors.toList())));
//        }
//        List<String> attachmentsImage = vo.getAttachmentsImage();
//        if(attachmentsImage != null && !attachmentsImage.isEmpty()) {
//            hazardInfo.setAttachmentsImage(String.join(",", attachmentsImage.stream().map(String::valueOf).collect(Collectors.toList())));
//        }
        BeanUtils.copyBeanProp(hazardInfo,vo);
        return hazardInfo;
    }

    @Override
    public List<HazardStatisticsVo> getHazardTypeStatistics(Long deptId) {
        return this.baseMapper.getHazardTypeStatistics(deptId);
    }

    @Override
    public List<HazardStatisticsVo> getHazardLevelStatistics(Long deptId) {
        return this.baseMapper.getHazardLevelStatistics(deptId);
    }

    @Override
    public List<HazardAmountAnalysisVo> getHazardAmountAnalysis(Long deptId) {
        return this.baseMapper.getHazardAmountAnalysis(deptId);
    }

    @Override
    public HazardAlarmVo getHazardAlarm(Long deptId, Long deltaId) {
        HazardAlarmVo vo = new HazardAlarmVo();
        HashMap<String,Object> delayedHazardAlarmInfo = this.baseMapper.getHazardAlarmInfo(deptId, deltaId,1);
        Long delayedDeltaTo =null,majorDeltaTo=null;
        if(delayedHazardAlarmInfo != null) {
            HazardAlarmRecord delayedRecord = new HazardAlarmRecord();
            Object hazardIdsObj = delayedHazardAlarmInfo.get("hazardIds");
            Object deltaIdObj = delayedHazardAlarmInfo.get("deltaId");
            if(hazardIdsObj != null) {
                String hazardIds = hazardIdsObj.toString();
                delayedRecord.setHazardIds(hazardIds);
            }
            if(deltaIdObj != null) {
                delayedDeltaTo = Long.valueOf(deltaIdObj.toString());
            }
            delayedRecord.setReceiveBy(SecurityUtils.getLoginUser().getUsername());
            delayedRecord.setReceiveTime(new Date());
            delayedRecord.setDeltaFrom(deltaId);
            delayedRecord.setDeltaTo(delayedDeltaTo);
            delayedRecord.setType("逾期");
            hazardAlarmRecordService.save(delayedRecord);
            vo.setDelayedRecord(delayedRecord);

        }
        HashMap<String,Object> majorHazardAlarmInfo = this.baseMapper.getHazardAlarmInfo(deptId, deltaId,0);
        if(majorHazardAlarmInfo != null) {
            HazardAlarmRecord majorRecord = new HazardAlarmRecord();
            Object hazardIdsObj = majorHazardAlarmInfo.get("hazardIds");
            Object deltaIdObj = majorHazardAlarmInfo.get("deltaId");
            if(hazardIdsObj != null) {
                String hazardIds = hazardIdsObj.toString();
                majorRecord.setHazardIds(hazardIds);
            }
            if(deltaIdObj != null) {
                majorDeltaTo = Long.valueOf(deltaIdObj.toString());
            }
            majorRecord.setReceiveBy(SecurityUtils.getLoginUser().getUsername());
            majorRecord.setReceiveTime(new Date());
            majorRecord.setDeltaFrom(deltaId);
            majorRecord.setDeltaTo(majorDeltaTo);
            majorRecord.setType("即将到期");
            hazardAlarmRecordService.save(majorRecord);
            vo.setMajorRecord(majorRecord);
        }
        // 安全比较 Long 类型
        if (delayedDeltaTo != null && (majorDeltaTo == null || delayedDeltaTo > majorDeltaTo)) {
            vo.setDeltaId(delayedDeltaTo);
        } else {
            vo.setDeltaId(majorDeltaTo);
        }
//        if(vo.getDeltaId() != null){
//            vo.setDeltaId(deltaId);
//        }
        return vo;
    }



    @Override
    public LambdaQueryWrapper<HazardInfo> getQueryWrapper(HazardInfoQo qo) {
        LambdaQueryWrapper<HazardInfo> queryWrapper = new LambdaQueryWrapper<>();
        //隐患类型
        if (StringUtils.hasText(qo.getType())) {
            queryWrapper.eq(HazardInfo::getType, qo.getType());
        }
        //隐患等级
        if (StringUtils.hasText(qo.getLevel())) {
            queryWrapper.eq(HazardInfo::getLevel, qo.getLevel());
        }
        //整改状态
        if(qo.getFinished() != null){
            queryWrapper.eq(HazardInfo::getFinished, qo.getFinished());
        }
        //单位
        if (qo.getDeptId()!=null) {
            queryWrapper.eq(HazardInfo::getDeptId, qo.getDeptId());
        }
        //内设机构
        if(qo.getSubDept() != null){
            queryWrapper.eq(HazardInfo::getSubDept, qo.getSubDept());
        }
        //监管等级
        if(StringUtils.hasText(qo.getSuperviseLevel())){
            queryWrapper.eq(HazardInfo::getSuperviseLevel, qo.getSuperviseLevel());
        }
//        if (StringUtils.hasText(qo.getStatus())) {
//            queryWrapper.eq(HazardInfo::getStatus, qo.getStatus());
//        }
//        if (qo.getHangup() != null) {
//            queryWrapper.eq(HazardInfo::getHangup, qo.getHangup());
//        }
        //检查时间
        if(qo.getCheckDateStart() != null){
            queryWrapper.ge(HazardInfo::getCheckDate, qo.getCheckDateStart());
        }
        if(qo.getCheckDateEnd() != null){
            queryWrapper.le(HazardInfo::getCheckDate, qo.getCheckDateEnd());
        }
        //整改完成
        if(qo.getFinishDateStart() != null){
            queryWrapper.ge(HazardInfo::getFinishDate, qo.getFinishDateStart());
        }
        if(qo.getFinishDateEnd() != null) {
            queryWrapper.le(HazardInfo::getFinishDate, qo.getFinishDateEnd());
        }

        //整改限期
        if(qo.getDeadlineStart() != null){
            queryWrapper.ge(HazardInfo::getDeadline, qo.getDeadlineStart());
        }
        if(qo.getDeadlineEnd() != null){
            // 将结束时间调整为当天的最后一秒
            java.time.LocalDateTime endOfDay = java.time.LocalDateTime.ofInstant(
                    qo.getDeadlineEnd().toInstant(),
                    java.time.ZoneId.systemDefault()
            ).with(java.time.LocalTime.MAX);
            queryWrapper.le(HazardInfo::getDeadline, java.util.Date.from(endOfDay.atZone(java.time.ZoneId.systemDefault()).toInstant()));
        }
        //关键字
        if (StringUtils.hasText(qo.getKeyword())) {
            //隐患描述
            queryWrapper.like(HazardInfo::getDescription, qo.getKeyword());
        }

        return queryWrapper;
    }

    @Override
    public void updateSuperviseLevelToNull(HazardInfo hazardInfo) {
        LambdaUpdateWrapper<HazardInfo> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(HazardInfo::getId, hazardInfo.getId()).set(HazardInfo::getSuperviseLevel, null);
        this.baseMapper.update(hazardInfo, updateWrapper);
    }
}

